--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit b716a2e0d22ae49bd55c56b0ca4381ab5211bc1f
Parents : 72414ca
Author : zenith <157907903+RFnexus@users.noreply.github.com>
Date : 2026-05-06T16:47:39-04:00
refactor(MicronParser): enable text inputs to upgrade to multilline textareas and display hint on pressing enter twice
Changes
2 files changed, 79 insertions(+), 2 deletions(-)
Diff
diff --git a/meshchatx/src/frontend/components/nomadnetwork/NomadNetworkPage.vue b/meshchatx/src/frontend/components/nomadnetwork/NomadNetworkPage.vue
index 3140a425..516107b2 100644
--- a/meshchatx/src/frontend/components/nomadnetwork/NomadNetworkPage.vue
+++ b/meshchatx/src/frontend/components/nomadnetwork/NomadNetworkPage.vue
@@ -493,6 +493,15 @@
v-html="renderedNodePageHtml"
></div>
<!-- eslint-enable vue/no-v-html -->
+ <Teleport to="body">
+ <div
+ v-if="multilineHintVisible"
+ class="multiline-hint pointer-events-none fixed bottom-3 right-3 px-2 py-1 rounded text-xs bg-amber-300 text-zinc-900 shadow"
+ style="z-index: 9999"
+ >
+ {{ $t("nomadnet.multiline_hint") }}
+ </div>
+ </Teleport>
</div>
<!-- file download bottom bar -->
@@ -661,6 +670,8 @@ export default {
partialRefreshByKey: {},
partialRefreshTimers: {},
processPartialsRaf: null,
+ multilineCleanup: null,
+ multilineHintVisible: false,
pathfinderInProgress: false,
pendingLoadLatestArchive: false,
@@ -876,6 +887,7 @@ export default {
this.loadedPartialIds = {};
}
this.scheduleProcessPartials();
+ this.$nextTick(() => this.refreshMultilineExpansion());
},
selectedNode: {
handler() {
@@ -900,6 +912,7 @@ export default {
this.nodesListAbortController?.abort();
this.nodeDetailAbortController?.abort();
this.clearPartials();
+ this.teardownMultilineExpansion();
WebSocketConnection.off("message", this.onWebsocketMessage);
},
@@ -1041,6 +1054,52 @@ export default {
this.processPartials();
});
},
+ teardownMultilineExpansion() {
+ if (typeof this.multilineCleanup === "function") {
+ try {
+ this.multilineCleanup();
+ } catch (e) {
+ console.warn("nomadnet: multiline cleanup failed", e);
+ }
+ }
+ this.multilineCleanup = null;
+ this.multilineHintVisible = false;
+ },
+ refreshMultilineExpansion() {
+ this.teardownMultilineExpansion();
+ if (this.isShowingNodePageSource) return;
+ if (this.nomadMicronWasmActive) return;
+ const path = this.nodePagePath || "";
+ const [pagePathWithoutData] = path.split("`");
+ if (!pagePathWithoutData.toLowerCase().endsWith(".mu")) return;
+ const container = this.$el?.querySelector?.(".nodeContainer");
+ if (!container) return;
+ const onArmed = (e) => {
+ e.detail?.element?.classList?.add("Mu-armed");
+ this.multilineHintVisible = true;
+ };
+ const onDisarmed = (e) => {
+ e.detail?.element?.classList?.remove("Mu-armed");
+ this.multilineHintVisible = false;
+ };
+ const onExpanded = (e) => {
+ e.detail?.element?.classList?.add("Mu-multiline");
+ this.multilineHintVisible = false;
+ };
+ container.addEventListener("micron-multiline-armed", onArmed);
+ container.addEventListener("micron-multiline-disarmed", onDisarmed);
+ container.addEventListener("micron-field-multiline-enabled", onExpanded);
+ const detach = MicronParser.enableDoubleEnterMultiline(container, {
+ windowMs: 500,
+ rows: 4,
+ });
+ this.multilineCleanup = () => {
+ container.removeEventListener("micron-multiline-armed", onArmed);
+ container.removeEventListener("micron-multiline-disarmed", onDisarmed);
+ container.removeEventListener("micron-field-multiline-enabled", onExpanded);
+ if (typeof detach === "function") detach();
+ };
+ },
openNomadnetPopout() {
if (!this.selectedNode) {
return;
@@ -1914,7 +1973,7 @@ export default {
if (options === "*") {
useCache = false; // we want to send another request with the field data
- const inputs = document.querySelectorAll(".nodeContainer input");
+ const inputs = document.querySelectorAll(".nodeContainer input, .nodeContainer textarea");
const inputValues = {};
@@ -1937,7 +1996,7 @@ export default {
const validNames = options.split("|");
// Select inputs within the container
- const inputs = document.querySelectorAll(".nodeContainer input");
+ const inputs = document.querySelectorAll(".nodeContainer input, .nodeContainer textarea");
const inputValues = {};
@@ -2389,6 +2448,23 @@ export default {
</script>
<style>
+.nodeContainer input.Mu-armed {
+ outline: 1px dashed #fbbf24;
+ outline-offset: 1px;
+}
+
+.nodeContainer textarea {
+ font: inherit;
+ color: inherit;
+ background: inherit;
+}
+
+.nodeContainer textarea.Mu-multiline {
+ outline: 1px solid #34d399;
+ outline-offset: 1px;
+ resize: vertical;
+}
+
.nodeContainer {
font-family: "Roboto Mono Nerd Font", ui-monospace, monospace;
letter-spacing: normal;
diff --git a/meshchatx/src/frontend/locales/en.json b/meshchatx/src/frontend/locales/en.json
index 7ea06503..e49ece29 100644
--- a/meshchatx/src/frontend/locales/en.json
+++ b/meshchatx/src/frontend/locales/en.json
@@ -1536,6 +1536,7 @@
"renderer_menu_js": "Micron: JavaScript",
"renderer_menu_wasm": "Micron: WebAssembly",
"renderer_setting_failed": "Could not update Micron renderer",
+ "multiline_hint": "Press Enter again to expand to multi-line",
"renderer_chip_markdown": "Markdown",
"renderer_chip_html": "HTML",
"renderer_chip_plaintext": "Text",
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────